package cn.px.service.upms.impl;


import cn.hutool.core.collection.CollectionUtil;
import com.github.pagehelper.PageHelper;
import cn.px.common.bean.AbstractPageResultBean;
import cn.px.common.bean.KeyValueObject;
import cn.px.common.enums.ResultCode;
import cn.px.common.exception.BusinessException;
import cn.px.common.util.BeanConverterUtil;
import cn.px.common.util.ListUtils;
import cn.px.common.util.MapUtils;
import cn.px.dao.bean.MyPage;
import cn.px.dao.dto.upms.SysRoleDTO;
import cn.px.dao.entity.upms.SysMenu;
import cn.px.dao.entity.upms.SysRole;
import cn.px.dao.entity.upms.SysUserRole;
import cn.px.dao.enums.SysUserClientIdEnum;
import cn.px.dao.mapper.upms.SysRoleMapper;
import cn.px.dao.mapper.upms.SysUserRoleMapper;
import cn.px.dao.vo.SysRoleVO;
import cn.px.dao.vo.SysUserRoleVO;
import cn.px.service.base.impl.BaseServiceImpl;
import cn.px.service.upms.SysMenuService;
import cn.px.service.upms.SysRoleMenuService;
import cn.px.service.upms.SysRoleService;
import cn.px.service.upms.SysUserRoleService;
import cn.px.service.util.DataField;
import cn.px.service.util.ExecuteSql;
import lombok.AllArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.weekend.Weekend;
import tk.mybatis.mapper.weekend.WeekendCriteria;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description 角色 service 实现类
 * @author 品讯科技
 * @date 2024-08
 * @Version Copyright (c) 2019,北京乾元坤和科技有限公司 All rights reserved.
 */
@AllArgsConstructor
@Service("sysRoleService")
public class SysRoleServiceImpl extends BaseServiceImpl<SysRoleMapper, SysRole, SysRoleDTO> implements SysRoleService {

    private final SysUserRoleMapper userRoleMapper;

    private final SysRoleMenuService sysRoleMenuService;

    private final SysMenuService sysMenuService;

    private final SysUserRoleService sysUserRoleService;

    private final CacheManager cacheManager;

    @Override
    public SysRole saveModelByDTO(SysRoleDTO model) {
        setCreateUserInfo(model);
        SysRole entity = BeanConverterUtil.copyObjectProperties(model, SysRole.class);
        setKey(entity);
        // 保存菜单角色关系
        List<String> menuIdList = model.getMenuIdList();
        sysRoleMenuService.saveByRoleMenus(entity.getRoleId(), menuIdList);
        mapper.insertSelective(entity);
        return entity;

    }

    @Override
    public void modModelByDTO(SysRoleDTO model) {
        setUpdateUserInfo(model);
        // 删除role与menu
        sysRoleMenuService.deleteByRoleId(model.getRoleId());
        // 保存菜单角色关系
        List<String> menuIdList = model.getMenuIdList();
        sysRoleMenuService.saveByRoleMenus(model.getRoleId(), menuIdList);
        mapper.updateByPrimaryKeySelective(BeanConverterUtil.copyObjectProperties(model, SysRole.class));
        // 删除用户缓存
        Cache cache = cacheManager.getCache("user_details");
        if (cache == null) {
            return;
        }
        List<SysUserRoleVO> sysUserRoleVOS = sysUserRoleService.selectVOByRoleId(model.getRoleId());
        sysUserRoleVOS.forEach(sysUserRoleVO -> cache.evict(sysUserRoleVO.getUsername()));
    }

    @Override
    public List<SysRole> selectListRolesByUserId(String userId) {
        // 查询用户角色关系
        Weekend<SysUserRole> weekend = new Weekend<>(SysUserRole.class);
        WeekendCriteria<SysUserRole, Object> weekendCriteria = weekend.weekendCriteria();
        weekendCriteria.andEqualTo(SysUserRole::getUserId, userId);
        List<SysUserRole> sysUserRoles = userRoleMapper.selectByExample(weekend);

        if (sysUserRoles.isEmpty()) {
            return new ArrayList<>(0);
        }
        // 查询对应的角色
        Weekend<SysRole> roleWeekend = new Weekend<>(SysRole.class);
        List<String> userIds = new ArrayList<>(sysUserRoles.size());
        sysUserRoles.forEach(user -> userIds.add(user.getRoleId()));
        roleWeekend.weekendCriteria().andIn("roleId", userIds);
        roleWeekend.orderBy(DataField.fnToFieldName(SysRole::getSort)).asc();
        return mapper.selectByExample(roleWeekend);
    }

    @Override
    public SysRoleVO selectRoleVOByRoleId(String roleId) {
        SysRole sysRole = super.getModelById(roleId);
        if (sysRole == null) {
            throw new BusinessException(ResultCode.BUSINESS_ROLE_IS_NULL);
        }
        SysRoleVO sysRoleVO = BeanConverterUtil.copyObjectProperties(sysRole, SysRoleVO.class);
        List<SysMenu> sysMenus = sysMenuService.selectMenuSortByRoleId(roleId);
        if (CollectionUtil.isNotEmpty(sysMenus)) {
            List<String> parentMenus = ListUtils.newArrayList();
            Map<String, String> map = MapUtils.newHashMap();
            sysMenus.forEach(one -> {
                String parentMenuId = one.getParentId();
                if (StringUtils.isNotBlank(parentMenuId) && map.get(parentMenuId) == null) {
                    parentMenus.add(parentMenuId);
                    map.put(parentMenuId, parentMenuId);
                }
            });
            List<KeyValueObject> valueObjects = sysMenus.stream()
                    .filter(menu -> map.get(menu.getMenuId()) == null)
                    .map(menu -> {
                        KeyValueObject keyValueObject = new KeyValueObject();
                        keyValueObject.setValue(menu.getMenuId());
                        keyValueObject.setName(menu.getName());
                        return keyValueObject;
                    }).collect(Collectors.toList());
            sysRoleVO.setMenus(valueObjects);
            sysRoleVO.setParentMenus(parentMenus);
        }

        return sysRoleVO;
    }

    @Override
    public void updateStatus(Integer status, List<String> roleIds) {
        Weekend<SysRole> weekend = new Weekend<>(SysRole.class);
        WeekendCriteria<SysRole, Object> weekendCriteria = weekend.weekendCriteria();
        weekendCriteria.andIn(SysRole::getRoleId, roleIds);
        SysRole update = new SysRole();
        update.setStatus(status);
        mapper.updateByExampleSelective(update, weekend);
    }

    @Override
    public AbstractPageResultBean<SysRole> selectPageInfo(SysRoleDTO record, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        return new MyPage<>(this.getModelListByDTO(record));
    }

    @Override
    public List<SysRole> getModelListByDTO(SysRoleDTO model) {
        Weekend<SysRole> weekend = new Weekend<>(SysRole.class);
        WeekendCriteria<SysRole, Object> weekendCriteria = weekend.weekendCriteria();
        ExecuteSql.executeNotBlank(model.getClientId(), () ->
                weekendCriteria.andEqualTo(SysRole::getClientId, model.getClientId()));
        if (model.getNotEnd() != null && model.getNotEnd()) {
            weekendCriteria.andNotEqualTo(SysRole::getClientId, SysUserClientIdEnum.END.getValue());
        }
        ExecuteSql.executeNotBlank(model.getClientId(), () ->
                weekendCriteria.andEqualTo(SysRole::getClientId, model.getClientId()));
        WeekendCriteria<SysRole, Object> orWeekendCriteria = weekend.weekendCriteria();
        if (StringUtils.isNotBlank(model.getKeyword())) {
            orWeekendCriteria.andLike(SysRole::getRoleName, "%" + model.getKeyword() + "%");
            orWeekendCriteria.orLike(SysRole::getRoleCode, "%" + model.getKeyword() + "%");
        }
        weekend.and(orWeekendCriteria);
        weekend.orderBy(DataField.fnToFieldName(SysRole::getSort)).asc();
        return mapper.selectByExample(weekend);
    }
}
